<?php
class ControllerResponse{
	private $commands;
	private $xml;
	private $encoding;
	private $portlet;
	private $isnew;
	public function __construct($portlet = '',$encoding = 'utf-8'){
		$this->setEncoding($encoding);
		$this->commands = array();
		$this->portlet = $portlet;
		$this->isnew = true;
	}
	public function isNew(){
		return $this->isnew;
	}
	public function setEncoding($encoding){
		$this->encoding = $encoding;
	}
	public function getEncoding(){
		return $this->encoding;
	}
	public function dialog($url,$width = 640,$height = 480,$scrollbars = false,$resizable = false){
		$resizable = $resizable?'1':'0';
		$scrollbars = $scrollbars?'1':'0';
		$this->script("cmspad.dialog('$url',$width,$height,$resizable,$scrollbars);");
		return $this;
	}
	public function confirm($sMessage,$yes = null,$no = null){
		$data = array();
		$data['q'] = $sMessage;
		if($yes){
			$data['y'] = $yes;
		}
		if($no){
			$data['n'] = $no;
		}
		$this->_command(array('n'=>'cc'),$data);
		return $this;
	}
	public function defer($script,$timeout,$loop = false){
		$loop = $loop?1:0;
		$timeout = intval($timeout);
		$this->_command(array('n'=>'ts','t'=>$timeout,'p'=>$loop),$script);
		return $this;
	}
	public function assign($sTarget,$sAttribute,$sData){
		$this->_command(array('n'=>'as','t'=>$sTarget,'p'=>$sAttribute),$sData);
		return $this;
	}
	public function style($sTarget,$sAttribute,$sData){
		$this->_command(array('n'=>'st','t'=>$sTarget,'p'=>$sAttribute),$sData);
		return $this;
	}
	public function append($sTarget,$sAttribute,$sData){
		$this->_command(array('n'=>'ap','t'=>$sTarget,'p'=>$sAttribute),$sData);
		return $this;
	}
	public function prepend($sTarget,$sAttribute,$sData){
		$this->_command(array('n'=>'pp','t'=>$sTarget,'p'=>$sAttribute),$sData);
		return $this;
	}
	public function refresh($target='s'){
		switch($target){
			case 't':
			case 'top':
				$target = 't';
				break;
			case 'o':
			case 'opener':
				$target = 'o';
				break;
			case 'p':
			case 'parent':
				$target = 'p';
				break;
			default:
				$target = 's';
				break;
		}
		$this->_command(array('n'=>'rl'),$target);
		return $this;
	}
	public function replace($sTarget,$sAttribute,$sSearch,$sData){
		$aData = array();
		$aData['s'] = $sSearch;
		$aData['r'] = $sData;
		$this->_command(array('n'=>'rp','t'=>$sTarget,'p'=>$sAttribute),$aData);
		return $this;
	}
	public function clear($sTarget,$sAttribute){
		$this->assign($sTarget,$sAttribute,'');
		return $this;
	}
	public function alert($sMsg){
		$this->_command(array('n'=>'al'),$sMsg);
		return $this;
	}
	public function redirect($sURL,$iDelay = 0){
		$queryStart = strpos($sURL,'?',strrpos($sURL,'/'));
		if($queryStart !== FALSE){
			$queryStart++;
			$queryEnd = strpos($sURL,'#',$queryStart);
			if($queryEnd === FALSE)
				$queryEnd = strlen($sURL);
			$queryPart = substr($sURL,$queryStart,$queryEnd - $queryStart);
			parse_str($queryPart,$queryParts);
			$newQueryPart = "";
			if($queryParts){
				$first = true;
				foreach($queryParts as $key=>$value){
					if($first)
						$first = false;
					else
						$newQueryPart .= ini_get('arg_separator.output');
					$newQueryPart .= rawurlencode($key) . '=' . rawurlencode($value);
				}
			}else if($_SERVER['QUERY_STRING']){
				$newQueryPart = rawurlencode($_SERVER['QUERY_STRING']);
			}
			$sURL = str_replace($queryPart,$newQueryPart,$sURL);
		}
		if($iDelay)
			$this->script('window.setTimeout("window.location = \'' . $sURL . '\';",' . ($iDelay * 1000) . ');');
		else
			$this->script('window.location = "' . $sURL . '";');
		return $this;
	}
	public function script($sJS){
		$this->_command(array('n'=>'js'),$sJS);
		return $this;
	}
	public function call(){
		$aArgs = func_get_args();
		$sFunc = array_shift($aArgs);
		$aData = array();
		for($i = 0,$l = $aArgs . length;$i < $l;$i++){
			$aData[] = json_encode($aArgs[$i]);
		}
		$this->_command(array('n'=>'jc','t'=>$sFunc),$aData);
		return $this;
	}
	public function remove($sTarget){
		$this->_command(array('n'=>'rm','t'=>$sTarget),'');
		return $this;
	}
	public function create($sParent,$sTag,$sId){
		$this->_command(array('n'=>'ce','t'=>$sParent,'p'=>$sId),$sTag);
		return $this;
	}
	public function insertBefore($sBefore,$sTag,$sId){
		$this->_command(array('n'=>'ib','t'=>$sBefore,'p'=>$sId),$sTag);
		return $this;
	}
	public function insertAfter($sAfter,$sTag,$sId){
		$this->_command(array('n'=>'ia','t'=>$sAfter,'p'=>$sId),$sTag);
		return $this;
	}
	public function createInput($sParent,$sType,$sName,$sId){
		$this->_command(array('n'=>'ci','t'=>$sParent,'p'=>$sId,'c'=>$sType),$sName);
		return $this;
	}
	public function insertInputBefore($sBefore,$sType,$sName,$sId){
		$this->_command(array('n'=>'ii','t'=>$sBefore,'p'=>$sId,'c'=>$sType),$sName);
		return $this;
	}
	public function insertInputAfter($sAfter,$sType,$sName,$sId){
		$this->_command(array('n'=>'iia','t'=>$sAfter,'p'=>$sId,'c'=>$sType),$sName);
		return $this;
	}
	public function addEvent($sTarget,$sEvent,$sHandler){
		$this->_command(array('n'=>'ae','t'=>$sTarget,'p'=>$sEvent),$sHandler);
		return $this;
	}
	public function removeEvent($sTarget,$sEvent,$sHandler){
		$this->_command(array('n'=>'re','t'=>$sTarget,'p'=>$sEvent),$sHandler);
		return $this;
	}
	public function includeScript($sFileName){
		$this->_command(array('n'=>'it'),$sFileName);
		return $this;
	}
	public function includeStyle($sFileName){
		$this->_command(array('n'=>'ie'),$sFileName);
		return $this;
	}
	public function getData(){
		$xml = '';
		if($this->commands){
			$xml = json_encode($this->commands);
		}
		return $xml;
	}
	public function setData($mCommands){
		if($mCommands instanceof ControllerResponse && !$mCommands->isNew()){
			$this->commands = array_merge($this->commands,$mCommands->commands);
		}else if(is_array($mCommands)){
			$this->commands = array_merge($this->commands,$mCommands);
		}else if(is_string($mCommands)){
			trigger_error("Using ControllerResponse->setData doesn't work with raw XML any more",E_USER_ERROR);
		}else{
			if(!empty($mCommands))
				trigger_error("The cmspad response output could not load other commands as data was not a valid array",E_USER_ERROR);
		}
	}
	private function _command($aAttributes,$mData){
		$aAttributes['v'] = $mData;
		$this->commands[] = $aAttributes;
		$this->isnew = false;
	}
}
class ControllerRequest{
	private $functions;
	private $fobjects;
	private $requesturi;
	private $encoding;
	private $fxmlarray;
	private $fposition;
	public function __construct($requesturi = '',$encoding = 'utf-8'){
		$this->functions = array();
		$this->fobjects = array();
		$this->requesturi = $requesturi;
		$this->encoding = $encoding;
		if(!$this->requesturi){
			if(!defined('CMSPAD_REQUEST_URI')){
				$this->requesturi = CMSPAD_RELPATH . 'index.php';
			}else{
				$this->requesturi = CMSPAD_REQUEST_URI;
			}
		}
	}
	public function registerFunction($mFunction){
		if(is_array($mFunction)){
			$this->functions[$mFunction[0]] = 1;
			$this->fobjects[$mFunction[0]] = array_slice($mFunction,1);
		}else{
			$this->functions[$mFunction] = 1;
		}
	}
	public function processRequests(){
		$isFileUpload = false;
		if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_GET['cpd']) && isset($_FILES)){
			$isFileUpload = true;
		}
		$this->processPostRequests($isFileUpload);
	}
	public function processPostRequests($isFileUpload){
		$sFunctionName = "";
		$bFoundFunction = true;
		$aArgs = array();
		$sFunctionName = isset($_POST["cpd"])?$_POST["cpd"]:false;
		$sFunctionTime = isset($_POST["cpdt"])?$_POST["cpdt"]:false;
		$aArgs = isset($_POST["cpda"])?$_POST["cpda"]:false;
		// File Upload Mode
		if($isFileUpload){
			if($sFunctionName === false){
				$sFunctionName = isset($_GET["cpd"])?$_GET["cpd"]:false;
			}
			if($sFunctionTime === false){
				$sFunctionTime = isset($_GET["cpdt"])?$_GET["cpdt"]:false;
			}
			if($aArgs === false){
				$aArgs = isset($_GET["cpda"])?$_GET["cpda"]:false;
			}
			if($aArgs !== false){
				$aArgs[] = $_POST;
			}
		}
		if(!$sFunctionName){
			header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
			header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
			header("Cache-Control: no-cache, must-revalidate");
			header("Pragma: no-cache");
		}
		if($bFoundFunction){
			if(!array_key_exists($sFunctionName,$this->functions)){
				$bFoundFunction = false;
				$oResponse = new ControllerResponse();
				$oResponse->alert("Unknown Function $sFunctionName.");
			}
		}
		if($bFoundFunction){
			$securityKey = null;
			if(defined('CMSPAD_SECURITY_KEY')){
				cmspad_import('util.SecurityUtil');
				$sFunctionTime = SecurityUtil::decrypt($sFunctionTime);
				$securityKey = md5($sFunctionName.'&'.$sFunctionTime);
			}
			for($i = 0,$il = count($aArgs);$i < $il;$i++){
				if(is_string($aArgs[$i])){
					if($securityKey){
						$aArgs[$i] = SecurityUtil::decrypt($aArgs[$i], $securityKey);
					}
					if(strpos($aArgs[$i],'{') === 0 || strpos($aArgs[$i],'[') === 0){
						$jsonItems = json_decode(stripslashes($aArgs[$i]),true);
						// 20080703: 处理提交数组问题
						$jsonObj = array();
						foreach($jsonItems as $jsonK=>$jsonV){
							// 20090830: 处理带Key的数组时有时需要先进行解码。
							$jsonK = urldecode($jsonK);
							//:~
							$jsonK = str_replace('[]','',$jsonK);
							$p1 = strpos($jsonK,'[');
							$p2 = strpos($jsonK,']');
							if($p1 !== false && $p2 !== false && $p1 < $p2){
								if(is_string($jsonV)){
									// String value
									$k = substr($jsonK,0,$p1);
									$a = substr($jsonK,$p1 + 1,$p2 - $p1 - 1);
									$jsonSubObj = isset($jsonObj[$k])?$jsonObj[$k]:array();
									if($a){
										$jsonSubObj[$a] =  $isFileUpload?$jsonV:rawurldecode($jsonV);
									}else{
										$jsonSubObj[] =  $isFileUpload?$jsonV:rawurldecode($jsonV);
									}
									$jsonObj[$k] = $jsonSubObj;
								}else{
									// Array value
									for($i = 0, $l = count($jsonV);$i < $l;$i++){
										$jsonV[$i] = $isFileUpload?$jsonV[$i]:rawurldecode($jsonV[$i]);
									}
									$jsonObj[$jsonK] = $jsonV;
								}
							}else{
								if(is_string($jsonV)){
									$jsonObj[$jsonK] =  $isFileUpload?$jsonV:rawurldecode($jsonV);
								}else{
									for($j = 0, $jl = count($jsonV);$j < $jl;$j++){
										$jsonV[$j] = $isFileUpload?$jsonV[$j]:rawurldecode($jsonV[$j]);
									}
									$jsonObj[$jsonK] = $jsonV;
								}
							}
						}
						//:~
						$aArgs[$i] = $jsonObj;
					}else{
						$aArgs[$i] = rawurldecode($aArgs[$i]);
					}
				}
			}
			if(!$this->_isFunctionCallable($sFunctionName)){
				$oResponse = new ControllerResponse();
				$oResponse->alert("The Registered Function $sFunctionName Could Not Be Found.");
			}else{
				$oResponse = $this->_callFunction($sFunctionName,$aArgs);
			}
		}
		$sContentHeader = "Content-Type: text/html;";
		if(is_a($oResponse,'ControllerResponse')){
			$outputString = $oResponse->getData();
		}else{
			// JSON output
			if(is_string($oResponse)){
				$outputString = $oResponse;
			}else{
				$outputString = json_encode($oResponse);
			}
		}
		if(defined('CMSPAD_SECURITY_KEY')){
			$outputString = SecurityUtil::encrypt($outputString, CMSPAD_SECURITY_KEY);
		}
		if($this->encoding && strlen(trim($this->encoding)) > 0){
			$sContentHeader .= " charset=" . $this->encoding;
		}
		header($sContentHeader);
		print $outputString;
		exit();
	}
	public function getJavascript($sJsURI = "",$sJsFile = NULL){
		global $_CONFIG;
		if($sJsURI != ""){
			if(substr($sJsURI,-1) != "/"){
				$sJsURI .= "/";
			}
		}else{
			$sJsURI = (isset($_CONFIG['DISPATCH']['SCRIPT'])?$_CONFIG['DISPATCH']['SCRIPT']:(CMSPAD_RELPATH.'index.php/')).'kernel/';
		}
		if($sJsFile == NULL){
			$sJsFile = 'controller.js';
		}
		$jsDirPath = CMSPAD_TEMPORARY_ABSPATH;
		$jsAbsPath = $jsDirPath . $sJsFile;
		$hasSecurityKey = defined('CMSPAD_SECURITY_KEY') && CMSPAD_SECURITY_KEY != '';
		if(CMSPAD_DEBUG || !file_exists($jsAbsPath)){
			$jsPackerClass = NULL;
			if($hasSecurityKey){
				$securityKey = ', SECURITY_KEY: "' . CMSPAD_SECURITY_KEY . '"';
			}else{
				$securityKey = '';
			}
			$jsScripts = "cmspad = {VERSION: 1.3, REQUEST_URI: \"{$this->requesturi}\"{$securityKey}, DEBUG: ".(CMSPAD_DEBUG?'true':'false').", DOCUMENT_ROOT: \"".cmspad_relative2relative('../')."\"};";
			$jsScripts .= file_get_contents(dirname(__FILE__) . '/controller/cmspad.js');
			if(defined('CMSPAD_DEBUG_CONSOLE') && CMSPAD_DEBUG_CONSOLE === true){
				$jsScripts .= file_get_contents(dirname(__FILE__) . '/controller/cmspad.console.js');
			}else{
				$jsScripts .= 'cmspad.apply(cmspad.console,{toggle:function(){},debug:function(msg){},warn:function(msg){},info:function(msg){},error:function(msg){alert(msg);},profile:function(label){},clear:function(){},isVisible:function(){return false;},hide:function(){},show:function(){},resize:function(size){},move:function( position ){}});';
			}
			if($hasSecurityKey){
				$jsScripts .= file_get_contents(dirname(__FILE__) . '/controller/cmspad.security.js');
			}
			$jsScripts .= file_get_contents(dirname(__FILE__) . '/controller/cmspad.ajax.js');
			$jsScripts .= file_get_contents(dirname(__FILE__) . '/controller/cmspad.core.js');
			foreach(array_keys($this->functions) as $sFunction){
				$jsScripts .= $this->_wrap($sFunction);
			}
			if(!CMSPAD_DEBUG){
				$jsPackerClass = cmspad_import('util.JavaScriptPacker');
				if($jsPackerClass){
					$jsScriptPacker = new $jsPackerClass($jsScripts);
					$jsPackedScripts = $jsScriptPacker->pack();
				}else{
					$jsPackedScripts = $jsScripts;
				}
			}else{
				$jsPackedScripts = $jsScripts;
			}
		}
		$html;
		if(CMSPAD_DEBUG){
			$html = "\t<script type=\"text/javascript\">$jsPackedScripts</script>\n";
		}else{
			$jsRelPath = $sJsURI . $sJsFile;
			if(!file_exists($jsAbsPath)){
				if(is_writable($jsDirPath)){
					$fp = fopen($jsAbsPath,'w');
					fwrite($fp,$jsPackedScripts);
					fclose($fp);
					if(extension_loaded('zlib')){
						// Output GZip cached file
						$gzfp = gzopen($jsAbsPath.'.gz','w');
						gzwrite($gzfp, file_get_contents($jsAbsPath));
						gzclose($gzfp);
						@chmod($jsAbsPath.'.gz',0777);
					}
					// For ftp users to delete cache file.
					@chmod($jsAbsPath,0777);
					@touch($jsAbsPath,filemtime(dirname(__FILE__) . '/controller'));
					$html = "\t<script type=\"text/javascript\" src=\"$jsRelPath\"></script>\n";
				}else{
					$html = "\t<script type=\"text/javascript\">$jsPackedScripts</script>\n";
				}
			}else{
				$html = "\t<script type=\"text/javascript\" src=\"$jsRelPath\"></script>\n";
			}
		}
		// 20080626: 加载语言包
		if(isset($_SESSION['cmspad']['language'])){
			$scriptFile = dirname(__FILE__) . '/controller/cmspad.nls_' . $_SESSION['cmspad']['language'] . '.js';
			if(CMSPAD_DEBUG){
				// DEBUG MODE
				if(file_exists($scriptFile)){
					$html .= "\t<script type=\"text/javascript\">" . file_get_contents($scriptFile) . "</script>\n";
				}
			}else{
				// CACHE MODE
				$scriptTemp = CMSPAD_TEMPORARY_ABSPATH . 'controller.' . $_SESSION['cmspad']['language'] . '.js';
				$scriptPath = $sJsURI . 'controller.' . $_SESSION['cmspad']['language'] . '.js';
				if(file_exists($scriptTemp)){
					$html .= "\t<script type=\"text/javascript\" src=\"" . $scriptPath . "\"></script>\n";
				}else{
					if(file_exists($scriptFile)){
						$nlsdata = file_get_contents($scriptFile);
						$jsPackerClass = cmspad_import('util.JavaScriptPacker');
						if($jsPackerClass){
							$jsScriptPacker = new $jsPackerClass($nlsdata);
							$nlsdata = $jsScriptPacker->pack();
						}
						file_put_contents($scriptTemp,$nlsdata);
						if(extension_loaded('zlib')){
							// Output GZip cached file
							$gzfp = gzopen($scriptTemp.'.gz','w');
							gzwrite($gzfp, $nlsdata);
							gzclose($gzfp);
							@chmod($scriptTemp.'.gz',0777);
						}
						$html .= "\t<script type=\"text/javascript\" src=\"" . $scriptPath . "\"></script>\n";
					}
				}
			}
		}else{
			$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
			if($acceptLanguage){
				if(strpos($acceptLanguage,';') > 0){
					$alangs = explode(',',substr($acceptLanguage,0,strpos($acceptLanguage,';')));
				}else{
					$alangs = explode(',',$acceptLanguage);
				}
				foreach($alangs as $alang){
					$alang = strtolower($alang);
					$scriptFile = dirname(__FILE__) . '/controller/cmspad.nls_' . $alang . '.js';
					if(CMSPAD_DEBUG){
						// DEBUG MODE
						if(file_exists($scriptFile)){
							$html .= "\t<script type=\"text/javascript\">" . file_get_contents($scriptFile) . "</script>\n";
							break;
						}
					}else{
						// CACHE MODE
						$scriptTemp = CMSPAD_TEMPORARY_ABSPATH . 'controller.' . $alang . '.js';
						$scriptPath = $sJsURI . 'controller.' . $alang . '.js';
						if(file_exists($scriptTemp)){
							$html .= "\t<script type=\"text/javascript\" src=\"" . $scriptPath . "\"></script>\n";
							break;
						}else{
							if(file_exists($scriptFile)){
								$nlsdata = file_get_contents($scriptFile);
								$jsPackerClass = cmspad_import('util.JavaScriptPacker');
								if($jsPackerClass){
									$jsScriptPacker = new $jsPackerClass($nlsdata);
									$nlsdata = $jsScriptPacker->pack();
								}
								file_put_contents($scriptTemp,$nlsdata);
								if(extension_loaded('zlib')){
									// Output GZip cached file
									$gzfp = gzopen($scriptTemp.'.gz','w');
									gzwrite($gzfp, $nlsdata);
									gzclose($gzfp);
									@chmod($scriptTemp.'.gz',0777);
								}
								$html .= "\t<script type=\"text/javascript\" src=\"" . $scriptPath . "\"></script>\n";
								break;
							}
						}
					}
				}
			}
		}
		//:~
		return $html;
	}
	private function _isObjectCallback($sFunction){
		if(array_key_exists($sFunction,$this->fobjects))
			return true;
		return false;
	}
	private function _isFunctionCallable($sFunction){
		if($this->_isObjectCallback($sFunction)){
			if(is_object($this->fobjects[$sFunction][0])){
				return method_exists($this->fobjects[$sFunction][0],$this->fobjects[$sFunction][1]);
			}else{
				return is_callable($this->fobjects[$sFunction]);
			}
		}else{
			return function_exists($sFunction);
		}
	}
	private function _callFunction($sFunction,$aArgs){
		if($this->_isObjectCallback($sFunction)){
			$mReturn = call_user_func_array($this->fobjects[$sFunction],$aArgs);
		}else{
			$mReturn = call_user_func_array($sFunction,$aArgs);
		}
		return $mReturn;
	}
	private function _wrap($sFunction){
		$js = "function cmspad$sFunction(){return cmspad.core._call(\"$sFunction\", arguments);};";
		return $js;
	}
}
class Controller{
	private static $singleton;
	private $request;
	public static function proxy(){
		// Cross domain proxy
		$rurl = $_POST['cpdp'];
		unset($_POST['cpdp']);
		$qs = '';
		$needStrip = get_magic_quotes_gpc();
		foreach($_POST as $k=>$v){
			if(is_array($v)){
				foreach($v as $kv=>$vv){
					if($needStrip){
						$vv = stripslashes($vv);
					}
					$qs .= $k . '[' . strval($kv) . ']=' . $vv . '&';
				}
			}else{
				if($needStrip){
					$v = stripslashes($v);
				}
				$qs .= $k . '=' . $v . '&';
			}
		}
		$cookie = '';
		foreach($_COOKIE as $key=>$value){
			$cookie .= $key . '=' . $value . '; ';
		}
		return cmspad_curl($rurl,trim($qs,'&'),$cookie);
	}
	public static function cache($pathinfo, $allowGZip){
		$file = CMSPAD_TEMPORARY_ABSPATH . substr($pathinfo,8);
		if(file_exists($file)){
			$stat = stat($file);
			$md5 = md5($stat['mtime'] . '=' . $stat['ino'] . '=' . $stat['size']);
			$etag = '"' . $md5 . '-' . crc32($md5) . '"';
			$mtime = $stat['mtime'];
			if((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mtime) || //
				 (isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) < $mtime) || //
				 (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag) //
			){
				header("HTTP/1.1 304 Not Modified");
				header('ETag:' . $etag);
				return true;
			}else{
				header('ETag:' . $etag);
			}
			$gmt_mtime = gmdate('D, d M Y H:i:s',$mtime) . ' GMT';
			header('Last-Modified:' . $gmt_mtime);
			$ext = array_pop(explode('.',$file));
			switch($ext){
				case 'css':
					header("Content-Type: text/css");
					break;
				case 'js':
					header("Content-Type: text/javascript");
					break;
				case 'gif':
					header("Content-Type: image/gif");
					break;
				case 'jpg':
					header("Content-Type: image/jpeg");
					break;
				case 'png':
					header("Content-Type: image/png");
					break;
				default:
					header("Content-Type: text/html");
			}
			if($allowGZip){
				$gzfile = $file . '.gz';
				if(file_exists($gzfile)){
					header('Content-Encoding: gzip');
					header('Content-Length: ' . filesize($gzfile));
					$fp = fopen($gzfile,'r');
					fpassthru($fp);
					fclose($fp);
				}else{
					ob_start('ob_gzhandler');
					$fp = fopen($file,'r');
					fpassthru($fp);
					fclose($fp);
					ob_flush();
				}
			}else{
				header('Content-Length: ' . filesize($file));
				$fp = fopen($file,'r');
				fpassthru($fp);
				fclose($fp);
			}
			return true;
		}else{
			return false;
		}
	}
	public static function newObject($portlet){
		if(is_object($portlet)){
			return $portlet;
		}else{
			$portletFile = self::getFile($portlet);
			if($portletFile){
				include $portletFile;
				$portletClass = cmspad_get_class_name($portlet);
				if($portletClass){
					return new $portletClass();
				}else{
					return false;
				}
			}else{
				return null;
			}
		}
	}
	public static function newMethod($portlet,$method){
		$portletObj = self::newObject($portlet);
		if($portletObj){
			$method = cmspad_get_function_name($method,$portletObj);
			if(method_exists($portletObj,$method)){
				return array(&$portletObj,$method);
			}else{
				return false;
			}
		}else{
			return $portletObj;
		}
	}
	public static function getInstance(){
		if(!self::$singleton){
			self::$singleton = new Controller();
		}
		return self::$singleton;
	}
	private static function getFile($portlet){
		$portletFile = CMSPAD_PORTLET_ABSPATH . $portlet . '.php';
		if(file_exists($portletFile)){
			return $portletFile;
		}else{
			return null;
		}
	}
	private function __construct(){
		$this->request = new ControllerRequest();
		$this->request->registerFunction(array('_flex',&$this,'_action_flex'));
		$this->request->registerFunction(array('_json',&$this,'_action_json'));
		$this->request->registerFunction(array('_call',&$this,'_action_call'));
		$this->request->registerFunction(array('_form',&$this,'_action_form'));
		$this->request->registerFunction(array('_view',&$this,'_action_view'));
		$this->request->registerFunction(array('_views',&$this,'_action_views'));
		$this->request->registerFunction(array('_link',&$this,'_action_link'));
		$this->request->registerFunction(array('_check',&$this,'_action_check'));
	}
	public function getControllerScripts(){
		return $this->request->getJavascript();
	}
	public function processRequests(){
		if(isset($_GET['CMSPAD_VERSION'])){
			echo CMSPAD_VERSION;
			return;
		}else if(isset($_GET['CMSPAD_COPYRIGHT'])){
			echo 'Copyright(c) 2008, cmspad.com all rights reserved.';
			return;
		}else if(isset($_GET['CMSPAD_AUTHOR'])){
			echo 'Yipsilon (yipsilon AT cmspad DOT com)';
			return;
		}else if(isset($_GET['CMSPAD_EDITION'])){
			echo 'Community';
			return;
		}
		if(isset($_POST['cpd']) || isset($_GET['cpd'])){
			$this->request->processRequests();
		}
	}
	public function _action_json($portlet,$method,$params = ''){
		$response = new ControllerResponse($portlet);
		$object = self::newMethod($portlet,self::wrapMethod('json',$method));
		if(is_array($object)){
			$arguments = self::wrapArgs($params);
			if($arguments){
				$json = call_user_func_array($object,$arguments);
			}else{
				$json = call_user_func($object);
			}
			unset($object);
		}else{
			if($object === null){
				$response->alert('Portlet File Not Found：' . $portlet);
			}else{
				$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $method);
			}
		}
		if(isset($json)){
			return $json;
		}else{
			return $response;
		}
	}
	public function _action_flex($portlet,$method,$params = ''){
		$object = self::newMethod($portlet,self::wrapMethod('flex',$method));
		if(is_array($object)){
			if($params){
				$json = call_user_func($object,$params);
			}else{
				$json = call_user_func($object);
			}
			unset($object);
			return $json;
		}else{
			return '';
		}
	}
	public function _action_call($portlet,$method,$params = null){
		$response = new ControllerResponse($portlet);
		$object = self::newMethod($portlet,self::wrapMethod('call',$method));
		if(is_array($object)){
			$arguments = self::wrapArgs($params,$response);
			if($arguments){
				call_user_func_array($object,$arguments);
			}else{
				call_user_func($object);
			}
			unset($object);
		}else{
			if($object === null){
				$response->alert('Portlet File Not Found：' . $portlet);
			}else{
				$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $method);
			}
		}
		return $response;
	}
	public function _action_check($portlet,$field,$value,$context = null){
		$response = new ControllerResponse($portlet);
		$object = self::newMethod($portlet,self::wrapMethod('check',$field));
		if(is_array($object)){
			call_user_func_array($object,array(&$response,$value,$context));
		}else{
			if($object === null){
				$response->alert('Portlet File Not Found：' . $portlet);
			}else{
				$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $field);
			}
		}
		unset($object);
		return $response;
	}
	public function _action_form($portlet,$method,$values){
		$response = new ControllerResponse($portlet);
		$filePath = CMSPAD_PORTLET_ABSPATH . $portlet . '.php';
		if(is_file($filePath)){
			include_once ($filePath);
			$portletObj = new $portlet();
			//+:20071215: 增加Portlet的验证方法 check<FormFieldName>(ControllerResponse, String, Array)
			$validated = true;
			if($values){
				foreach($values as $k=>$v){
					$validator = self::newMethod($portletObj,self::wrapMethod('check',$k));
					if(is_array($validator)){
						$r = call_user_func_array($validator,array(&$response,$v,$values));
						if($r !== false){
							continue;
						}else{
							$validated = false;
							break;
						}
					}
				}
			}
			//:~
			if($validated){
				$object = self::newMethod($portletObj,self::wrapMethod('form',$method));
				if(is_array($object)){
					call_user_func_array($object, array(&$response,$values));
				}else{
					if($object === null){
						$response->alert('Portlet File Not Found：' . $portlet);
					}else{
						$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $method);
					}
				}
			}
			unset($portletObj);
		}else{
			$response->alert("Portlet Not Found: $filePath");
		}
		return $response;
	}
	public function _action_view($target,$portlet,$method,$params = ''){
		$response = new ControllerResponse($portlet);
		$object = self::newMethod($portlet,self::wrapMethod('view',$method));
		if(is_array($object)){
			$arguments = self::wrapArgs($params);
			if($arguments){
				$return = call_user_func_array($object,$arguments);
			}else{
				$return = call_user_func($object);
			}
			if(is_string($return) && $return != ''){
				$response->assign($target,'innerHTML',$return);
			}
		}else{
			if($object === null){
				$response->alert('Portlet File Not Found：' . $portlet);
			}else{
				$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $method);
			}
		}
		unset($object);
		return $response;
	}
	public function _action_views($portlets){
		$responses = new ControllerResponse();
		$portletObjs = array();
		foreach($portlets as $exp){
			$portletIndex0 = strpos($exp,':');
			$id = substr($exp,0,$portletIndex0);
			$exp = substr($exp,$portletIndex0 + 1);
			$portletIndex1 = strpos($exp,'.');
			$portletIndex2 = strpos($exp,'(');
			$portletIndex3 = strrpos($exp,')');
			$portletClass = substr($exp,0,$portletIndex1);
			$portletMethod = substr($exp,$portletIndex1 + 1,$portletIndex2 - $portletIndex1 - 1);
			$portletObj = isset($portletObjs[$portletClass . '.' . $portletMethod])?$portletObjs[$portletClass . '.' . $portletMethod]:false;
			if(!$portletObj){
				$portletObj = self::newMethod($portletClass,self::wrapMethod('view',$portletMethod));
				if(is_array($portletObj)){
					$portletObjs[$portletClass . '.' . $portletMethod] = $portletObj;
				}else{
					if($portletObj === null){
						$response->alert('Portlet File Not Found：' . $portletClass);
					}else{
						$response->alert('Portlet Class Or Method Not Found：' . $portletClass . '.' . $portletMethod);
					}
					continue;
				}
			}
			if($portletIndex3 != $portletIndex2 + 1){
				$params = substr($exp,$portletIndex2 + 1,strlen($exp) - $portletIndex2 - 2);
				$arguments = self::wrapArgs($params);
				$return = call_user_func_array($portletObj,$arguments);
			}else{
				$return = call_user_func($portletObj);
			}
			$response = new ControllerResponse($portletClass);
			if(is_string($return) && $return != ''){
				$response->assign($id,'innerHTML',$return);
			}
			$responses->setData($response);
		}
		foreach($portletObjs as $portletObj){
			unset($portletObj);
		}
		return $responses;
	}
	public function _action_link($portlet,$method,$params = ''){
		$response = new ControllerResponse($portlet);
		$object = self::newMethod($portlet,self::wrapMethod('link',$method));
		if(is_array($object)){
			$arguments = self::wrapArgs($params,$response);
			if($arguments){
				call_user_func_array($object,$arguments);
			}else{
				call_user_func_array($object,array(&$response));
			}
			unset($object);
		}else{
			if($object === null){
				$response->alert('Portlet File Not Found：' . $portlet);
			}else{
				$response->alert('Portlet Class Or Method Not Found：' . $portlet . '.' . $method);
			}
		}
		return $response;
	}
	public static function wrapMethod($prefix,$method){
		return $prefix . ucfirst($method);
	}
	private static function wrapArgs($params,&$response = null){
		if($params){
			$arguments = array();
			if($response){
				$arguments[] = &$response;
			}
			$args = explode(',',$params);
			for($i = 0,$l = count($args);$i < $l;$i++){
				$arg = trim($args[$i]);
				$argf = substr($arg,0,1);
				if($argf == "'" || $argf == '"'){
					$arg = substr($arg,1);
				}
				$argl = strlen($arg) - 1;
				$argr = substr($arg,$argl,1);
				if($argr == "'" || $argr == '"'){
					$arg = substr($arg,0,$argl);
				}
				$arguments[] = $arg;
			}
			return $arguments;
		}else{
			return $response?array(&$response):array();
		}
	}
}
?>